package org.travelfusion.xmlclient.ri.handler.misc;

import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.XMLStreamConstants;

import org.travelfusion.xmlclient.handler.HandlesRequestsFor;
import org.travelfusion.xmlclient.impl.handler.AbstractXmlToolRequestStAXResponseHandler;
import org.travelfusion.xmlclient.ri.xobject.misc.XBound;
import org.travelfusion.xmlclient.ri.xobject.misc.XFindCheapestPricesRequest;
import org.travelfusion.xmlclient.ri.xobject.misc.XFindCheapestPricesRequest.ResultsPolicy;
import org.travelfusion.xmlclient.ri.xobject.misc.XFindCheapestPricesResponse;
import org.travelfusion.xmlclient.ri.xobject.misc.XItem;
import org.travelfusion.xmlclient.util.TfXAPIUtil;

@HandlesRequestsFor(XFindCheapestPricesRequest.class)
public class FindCheapestPricesHandler extends
    AbstractXmlToolRequestStAXResponseHandler<XFindCheapestPricesRequest, XFindCheapestPricesResponse> {

  @Override
  protected void fillTemplate() throws Exception {

    template.gotoChild();

    template.gotoChild("MaxCount").addText(Integer.toString(request.getMaxCount()));

    template.gotoChild("RoundTrip").addText(Boolean.toString(request.isRoundTrip()));

    template.gotoChild("Currency").addText(request.getCurrency());

    template.gotoChild("ResultsPolicy").addText(request.getResultsPolicy() == ResultsPolicy.CHEAPEST ? "cheapest" : "random");

    template.gotoChild("OriginList");
    template.gotoChild("Code").delete();
    List<String> origins = request.getOrigins();
    for (String origin : origins) {
      template.addTag("Code").addText(origin);
    }
    template.gotoParent();

    template.gotoChild("DestinationList");
    template.gotoChild("Code").delete();
    List<String> destinations = request.getDestinations();
    for (String destination : destinations) {
      template.addTag("Code").addText(destination);
    }
  }

  @Override
  public XFindCheapestPricesResponse handleResponse() throws Exception {
    StringBuilder builder = new StringBuilder(32);
    List<XItem> itemList = new ArrayList<XItem>();
    String currentName = null;
    XItem item = null;
    XBound outbound = null;
    XBound inbound = null;

    done: for (int event; ((event = responseReader.next()) != XMLStreamConstants.END_DOCUMENT);) {
      switch (event) {
        case XMLStreamConstants.START_ELEMENT:
          builder.setLength(0);
          currentName = responseReader.getName().getLocalPart();
          if (item == null) {
            if ("Item".equals(currentName)) {
              item = new XItem();
            }
          }
          else {
            if (outbound == null) {
              if ("Outward".equals(currentName)) {
                outbound = new XBound();
              }
            }
            if (inbound == null) {
              if ("Return".equals(currentName)) {
                inbound = new XBound();
              }
            }
          }
          break;

        case XMLStreamConstants.CHARACTERS:
          if (item != null) {
            builder.append(responseReader.getTextCharacters(), responseReader.getTextStart(), responseReader.getTextLength());
          }
          break;

        case XMLStreamConstants.END_ELEMENT:
          if (item != null) {
            currentName = responseReader.getName().getLocalPart();
            if (outbound != null) {
              if ("OperatorCode".equals(currentName)) {
                outbound.setOperatorCode(builder.toString().trim());
              }
              else if ("OperatorName".equals(currentName)) {
                outbound.setOperatorName(builder.toString().trim());
              }
              else if ("FlightNo".equals(currentName)) {
                outbound.setFlightNo(builder.toString().trim());
              }
              else if ("DepartDate".equals(currentName)) {
                outbound.setDepartDate(builder.toString().trim());
              }
              else if ("ArriveDate".equals(currentName)) {
                outbound.setArriveDate(builder.toString().trim());
                item.setOutbound(outbound);
                outbound = null;
              }
            }

            if (inbound != null) {
              if ("OperatorCode".equals(currentName)) {
                inbound.setOperatorCode(builder.toString().trim());
              }
              else if ("OperatorName".equals(currentName)) {
                inbound.setOperatorName(builder.toString().trim());
              }
              else if ("FlightNo".equals(currentName)) {
                inbound.setFlightNo(builder.toString().trim());
              }
              else if ("DepartDate".equals(currentName)) {
                inbound.setDepartDate(builder.toString().trim());
              }
              else if ("ArriveDate".equals(currentName)) {
                inbound.setArriveDate(builder.toString().trim());
                item.setInbound(inbound);
                inbound = null;
              }
            }

            if ("Origin".equals(currentName)) {
              item.setOrigin(builder.toString().trim());
            }
            else if ("Destination".equals(currentName)) {
              item.setDestination(builder.toString().trim());
            }
            else if ("Price".equals(currentName)) {
              item.setPrice(builder.toString().trim());
            }
            else if ("Timestamp".equals(currentName)) {
              item.setTimestamp(TfXAPIUtil.parseDate(builder.toString().trim()));
            }
            else if ("Item".equals(currentName)) {
              itemList.add(item);
              item = null;
            }
          }
          else if ("FindCheapestPrices".equals(currentName)) {
            break done;
          }
          currentName = null;
          break;
      }
    }

    XFindCheapestPricesResponse response = new XFindCheapestPricesResponse();
    response.setItemList(itemList);
    return response;
  }

}
